﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Sinacor.Infra.Common.Caching;
using Sinacor.Infra.Service.Data;
using System.Data.Common;
using System.Data;

namespace Sinacor.Infra.Service.Logic
{
    /// <summary>
    /// Classe de leitura de configuração de Actions
    /// Singleton class
    /// </summary>
    internal class ActionConfigReader
    {
        private static ActionConfigReader _reader;

        private static string CacheEntryName = "ActionConfigReader.ActionConfigs";
        private static TimeSpan CacheTimeOut = new TimeSpan(0, 30, 0); ///TODO: permitir configurar isso
        private static object _createLock = new object();
        private object _readLock = new object();

        private ActionConfigReader()
        {
        }

        /// <summary>
        /// Retorna uma instância da classe ActionConfigReader
        /// </summary>
        /// <returns></returns>
        internal static ActionConfigReader GetInstance()
        {
            lock (_createLock)
            {
                if (_reader == null)
                    _reader = new ActionConfigReader();
            }
            return _reader;
        }

        /// <summary>
        /// Lê e retorna as configurações de uma Action
        /// </summary>
        /// <param name="module">Módulo ao qual a Action pertence</param>
        /// <param name="subModule">Sub-Módulo ao qual a Action pertence</param>
        /// <param name="actionName">Nome de Action</param>
        /// <returns></returns>
        internal ActionConfig Read(string actionName)
        {
            Dictionary<string, ActionConfig> configs;

            ActionConfig config = new ActionConfig();
            config.ActionName = actionName;
            
            lock (_readLock)
            {
                //se nao ha no cache dados de config
                if (!Cache.Contains(CacheEntryName) || Cache.GetData(CacheEntryName) == null)
                {
                    configs = new Dictionary<string, ActionConfig>();
                    Cache.Add(ActionConfigReader.CacheEntryName, configs, ActionConfigReader.CacheTimeOut);//timeout de 2hrs
                }
                else
                {
                    configs = Cache.GetData(ActionConfigReader.CacheEntryName) as Dictionary<string, ActionConfig>;
                }

                //se nao existe no cache o config
                if (!configs.ContainsKey(config.ActionName))
                {
                    //recuperar
                    config = RetrieveActionConfig(actionName);

                    if (config != null)
                    {
                        lock (configs)
                        {
                            configs.Add(config.ActionName, config);
                        }
                    }
                    else
                        throw new Exception("Doesn't exists a valid configuration for the informed Action.");
                }
                else
                {
                    config = configs[config.ActionName];
                }
            }

            return config;
        }

        /// <summary>
        /// Recuperar a configuração da ação
        /// </summary>
        /// <returns></returns>
        private ActionConfig RetrieveActionConfig(string actionName)
        {
            ActionConfig config = null;
            string query = "SELECT COD_EXEC_SERV, NOME_EXEC_SERV, NOME_MET_BASI, NOME_MET_ADIC, COD_TIPO_MET_EXEC FROM TFWEXEC_SERV WHERE NOME_EXEC_SERV = :NOME_EXEC_SERV";

            using (OracleDataBase db = new OracleDataBase())
            {
              using (DbCommand command = db.GetSqlStringCommand(query))
              {
                db.AddInParameter(command, "NOME_EXEC_SERV", DbType.String, actionName);

                using (IDataReader reader = db.ExecuteReader(command))
                {
                  if (reader.Read())
                  {
                    config = new ActionConfig();
                    config.ActionName = actionName;
                    config.Method = reader.GetValue<string>("NOME_MET_BASI");
                    config.AlternativeMethod = reader.GetValue<string>("NOME_MET_ADIC");
                    config.IsKernelPlusAction = (reader.GetValue<string>("COD_TIPO_MET_EXEC") == "S");
                  }
                }
              }
            }
            return config;
        }
    }
}
